import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:ivy_baby_record/ivy_baby_record.dart';
import 'package:ivy_baby_record/user/api/record/day_log_rsp.dart';
import 'package:ivy_baby_record/user/colors/colors.dart';
import 'package:ivy_baby_record/user/db/user_database_util.dart';
import 'package:ivy_baby_record/user/global/global_info.dart';
import 'package:ivy_baby_record/user/model/record/day_log.dart';
import 'package:ivy_baby_record/user/model/record/has_record.dart';
import 'package:ivy_baby_record/user/model/record/weekday_info.dart';
import 'package:ivy_baby_record/user/pages/base/base_page.dart';
import 'package:ivy_baby_record/user/pages/record/record_notifier.dart';
import 'package:ivy_baby_record/user/pages/record/record_util.dart';
import 'package:ivy_baby_record/user/util/child_util.dart';
import 'package:ivy_baby_record/user/util/datetime.dart';
import 'package:ivy_baby_record/user/util/ui_util.dart';
import 'package:ivy_baby_record/user/util/user_util.dart';
import 'package:ivy_baby_record/user/widget/weekly_calendar.dart';
import 'package:ivybaby_api/api/base/api_base.dart';
import 'package:ivy_baby_record/user/api/record/record_api.impl.dart';
import 'package:ivybaby_api/api/config/global_data.dart';
import 'package:provider/provider.dart';

typedef DateSwitchCallback = void Function(DateTime dateTime);

class RecordHomePage extends BasePage {
  @override
  State<StatefulWidget> createState() => _RecordHomePageState();
}

class _RecordHomePageState extends BasePageState<RecordHomePage> {
  late PageController _pageController;
  int _currentPage = 0;
  int _weeks = 1;
  int _dayIndex = 0;
  String _curDateAge = '';
  late List<String?> _dateList;
  late RecordNotifier _recordNotifier;
  late WeeklyCalendar weeklyCalendar;
  final babyId = GlobalInfo.inst.childId;

  @override
  String get title => '记录';

  @override
  bool get isWithUnderline => true;

  @override
  void dispose() {
    super.dispose();
    IvyBabyRecord.release('calendar_ic');
  }

  @override
  void initState() {
    _recordNotifier = RecordNotifier();
    super.initState();

    _recordNotifier.curDate = DateTimeUtil.formatYMDChinese(DateTime.now());
    UIUtils.loadImageTexture(['calendar_ic']).then((value) {
      _recordNotifier.updateCalendarId(value['calendar_ic']!);
    });

    init();

    _pageController = PageController();
    _pageController.addListener(() {
      var offset = _pageController.offset;
      var page = _pageController.page;
    });

    if (UserUtils.isGuest()) {
      /// 游客无需进行后续操作
      return;
    }

    _recordNotifier.hasRecordMap?.clear();
    Future<List<HasRecord>> hasRecordFuture = Future(() async {
      return UserDatabaseUtil.inst.database.hasRecordDao.findHasRecordById(babyId);
    });
    hasRecordFuture.then((value) {
      if (value != null && value.isNotEmpty) {
        /// 数据库中有记录，读取数据到内存中
        for (HasRecord item in value) {
          _recordNotifier.hasRecordMap[item.key] = item;
        }
      } else {
        /// 数据库中无记录
      }
    });

    /// 记录小圆点，先取时间戳，再增量查询
    Future<HasRecordsTs?> tsFuture = Future(() async {
      return UserDatabaseUtil.inst.database.hasRecordsTsDao.findHasRecordTsByBabyId(babyId);
    });
    tsFuture.then((value) {
      Future<GetHasRecordsResponse> hasRecordFuture;
      bool isFirst = false;
      if (value != null) {
        hasRecordFuture = ApiUtils.inst.getHasRecords(dgts: value.dgts, dots: value.dots,
            dpts: value.dpts, dptsg: value.dptsg,
            hgts: value.hgts, hots: value.hots,
            hpts: value.hpts, hptsg: value.hptsg);
      } else {
        isFirst = true;
        hasRecordFuture = ApiUtils.inst.getHasRecords();
      }

      hasRecordFuture.then((value) {
        if (value.isSuccess && value.data != null) {
          /// 接口成功后，首次插入时间戳，否则更新时间戳
          value.data!.babyId = babyId;
          if (isFirst) {
            UserDatabaseUtil.inst.database.hasRecordsTsDao.insertHasRecordTs(value.data!);
          } else {
            UserDatabaseUtil.inst.database.hasRecordsTsDao.updateHasRecordTs(value.data!);
          }

          /// 保存圆点数据
          if (value.data!.rs != null && value.data!.rs.isNotEmpty) {
            for (HasRecord item in value.data!.rs) {
              item.babyId = babyId;
              item.key = '$babyId-${item.day}-${item.type}';
              if (item.has != 1) {
                _recordNotifier.hasRecordMap.remove(item.key);
              } else {
                _recordNotifier.hasRecordMap[item.key] = item;
              }
            }
          }

          Future(() async{
            for (HasRecord item in value.data!.rs) {
              if (item.has != 1) {
                UserDatabaseUtil.inst.database.hasRecordDao.deleteHasRecord(item);
              } else {
                UserDatabaseUtil.inst.database.hasRecordDao.insertHasRecord(item);
              }
            }
          });
        }
      });
    });

    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      _pageController.jumpToPage(_dayIndex);
    });
  }

  @override
  Widget buildContent(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => _recordNotifier,
      child: Consumer<RecordNotifier>(
        builder: (context, notifier, child) {
          return Column(
            children: [
              buildCalendarPagerView(context),
              Container(
                color: CustomColors.c1,
                height: 30,
                child: Center(
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      Container(
                        width: 18,
                        height: 18,
                        child: UIUtils.getWidgetByTextureId(notifier.calendarId),
                      ),
                      SizedBox(width: 15),
                      Text(notifier.curDate,
                          style: TextStyle(color: CustomColors.c4, fontSize: 14)),
                      Text(_curDateAge,
                          style: TextStyle(color: CustomColors.c4, fontSize: 14))
                    ],
                  ),
                ),
              ),
              buildDayLogPagerView(context),
            ],
          );
        },
      ),
    );
  }

  Widget buildCalendarPagerView(BuildContext context) {
    DateTime cur = DateTime.now();
    DateTime min = cur.subtract(Duration(days: 20));
    DateTime max = cur.add(Duration(days: 15));

    return weeklyCalendar = WeeklyCalendar(
        min: min,
        max: max,
        cur: cur,
        callback: (dateTime) {
          _recordNotifier.updateCurDate(DateTimeUtil.formatYMDChinese(dateTime));
          String date = DateTimeUtil.formatDefaultDate(dateTime);
          for (int i = 0; i < _dateList.length; ++i) {
            if (_dateList[i] == date) {
              if (_pageController.hasClients && _currentPage != i) {
                _pageController?.jumpToPage(i);
              }
              break;
            }
          }
        });
  }

  Widget buildDayLogPagerView(BuildContext context) {
    return Container(
      child: Expanded(
        child: SizedBox(
          child: PageView.builder(
              onPageChanged: (index) {
                _currentPage = index;
                _recordNotifier.updateSelectDate(DateTime.parse(_dateList[index]!));
                getDayLog(_dateList[index]!);
              },
              reverse: false,
              physics: BouncingScrollPhysics(),
              scrollDirection: Axis.horizontal,
              controller: _pageController,
              itemCount: _weeks * 7,
              itemBuilder: (context, index) {
                return buildDayLogListView(context, index);
              }),
        ),
      ),
    );
  }

  Widget buildDayLogListView(BuildContext context, int pageIndex) {
    return Container(
      child: Consumer<RecordNotifier>(
        builder: (context, notifier, child) {
          return Column(
            children: [
              ListView.separated(
                  scrollDirection: Axis.vertical,
                  separatorBuilder: (context, index) {
                    return Divider(height: 10, color: Colors.transparent);
                  },
                  shrinkWrap: true,
                  physics: NeverScrollableScrollPhysics(),
                  padding: EdgeInsets.only(top: 12),
                  itemCount: notifier.dataMap[pageIndex]?.length ?? 0,
                  itemBuilder: (context, index) {
                    return buildDayLogItemView(context, notifier.dataMap[pageIndex]!, index);
                  }
              ),
              Consumer<RecordNotifier>(
                builder: (context, notifier, child) {
                  return Offstage(
                    offstage: (notifier.dataMap[pageIndex]?.length ?? 0) > 0,
                    child: Container(
                      child: Text('Empty View : ${_dateList[pageIndex]}'),
                    ),
                  );
                },
              ),
            ],
          );
        },
      ),
    );
  }

  Widget buildDayLogItemView(
      BuildContext context, List<DayLog> list, int index) {
    DayLog record = list[index];
    return Container(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            margin: EdgeInsets.only(left: 12, top: 14),
            child: Text(
              record.eventTime.split(' ')[1].substring(0, 5),
              style: TextStyle(fontSize: 12, color: CustomColors.c4)
            ),
          ),
          Expanded(
            child: Container(
              margin: EdgeInsets.symmetric(horizontal: 12),
              padding: RecordUtil.getRecordItemPadding(record),
              alignment: Alignment.topLeft,
              decoration: ShapeDecoration(
                  color: RecordUtil.getRecordItemColor(record.type),
                  shape: RoundedRectangleBorder(
                    side: BorderSide.none,
                    borderRadius: BorderRadius.all(Radius.circular(2))
                  ),
              ),
              child: ConstrainedBox(
                constraints: BoxConstraints(minHeight: 20),
                child: RecordUtil.getRecordItem(record),
              ),
            ),
          ),
        ],
      ),
    );
  }

  void init() {
    DateTime cur = DateTimeUtil.getStartDateTime(DateTime.now());
    DateTime min = cur.subtract(Duration(days: 20));
    DateTime max = cur.add(Duration(days: 15));

    _recordNotifier.selectDate = cur;
    int weekdayIndex = cur.weekday % 7;
    DateTime _curWeekStart = cur.subtract(Duration(days: weekdayIndex));
    DateTime _curWeekEnd = cur.add(Duration(days: 7 - (weekdayIndex + 1)));

    var startDiffDays = _curWeekStart.difference(min).inDays.abs();
    var weeksBeforeCurWeek =
        startDiffDays ~/ 7 + (startDiffDays % 7 == 0 ? 0 : 1);
    var endDiffDays = _curWeekEnd.difference(max).inDays.abs();
    var weeksAfterCurWeek = endDiffDays ~/ 7 + (endDiffDays % 7 == 0 ? 0 : 1);
    _weeks = 1 + weeksBeforeCurWeek + weeksAfterCurWeek;

    List<WeekdayInfo?> _list = List.filled(_weeks, null);
    WeekdayInfo curWeekdayInfo = WeekdayInfo(_curWeekStart, _curWeekEnd);
    _list[weeksBeforeCurWeek] = curWeekdayInfo;

    var lastWeekEnd = _curWeekStart.subtract(Duration(days: 1));
    var lastWeekStart = lastWeekEnd.subtract(Duration(days: 7 - 1));

    for (var i = weeksBeforeCurWeek - 1; i >= 0; --i) {
      WeekdayInfo weekdayInfo = WeekdayInfo(lastWeekStart, lastWeekEnd);
      _list[i] = weekdayInfo;
      lastWeekEnd = lastWeekStart.subtract(Duration(days: 1));
      lastWeekStart = lastWeekEnd.subtract(Duration(days: 7 - 1));
    }

    lastWeekStart = _curWeekEnd.add(Duration(days: 1));
    for (var i = weeksBeforeCurWeek + 1; i < _weeks; ++i) {
      lastWeekEnd = lastWeekStart.add(Duration(days: 7 - 1));
      WeekdayInfo weekdayInfo = WeekdayInfo(lastWeekStart, lastWeekEnd);
      _list[i] = weekdayInfo;
      lastWeekStart = lastWeekEnd.add(Duration(days: 1));
    }

    initDateList(_list);
    _dayIndex = -1;
    int i = 0;
    for (var week in _list) {
      var start = week!.start.subtract(Duration(days: 1));
      var end = week.end.add(Duration(days: 1));
      if (cur.isBefore(end) && cur.isAfter(start)) {
        for (int j = 0; j < 7; ++j) {
          if (cur.isAtSameMomentAs(week.start.add(Duration(days: j)))) {
            _dayIndex = i * 7 + j;
            _currentPage = _dayIndex;
            break;
          }
        }
      }
      if (_dayIndex >= 0) {
        break;
      }
      ++i;
    }
  }

  void initDateList(List<WeekdayInfo?> list) {
    int i = 0;
    _dateList = List.filled(_weeks * 7, null);
    for (var week in list) {
      for (int j = 0; j < 7; ++j) {
        _dateList[i * 7 + j] = DateTimeUtil.formatDefaultDate(week!.start.add(Duration(days: j)));
      }
      ++i;
    }
  }

  void getDayLog(String date) {
    Future<List<DayLog>> cacheFuture = new Future(() async {
      return UserDatabaseUtil.inst.database.dayLogDao.findDayLogByDate(date.split(' ')[0]);
    });

    cacheFuture.then((cache) {
      if (cache != null && cache.isNotEmpty) {
        /// 有缓存数据， 先展示
        RecordUtil.sortRecord(cache, true);
        _recordNotifier.updateData(_currentPage, cache);
      }

      Future<GetDayLogRsp> future;
      if (ChildUtil.isCurPregnant()) {
        future = ApiUtils.inst.getGravidDayLog(
            date,
            GlobalData.appDevice.userId.toString(),
            GlobalInfo.inst.childId);
      } else {
        future = ApiUtils.inst.getDayLog(
            date,
            GlobalData.appDevice.userId.toString(),
            GlobalInfo.inst.childId);
      }

      future.then((value) {
        if (value.isSuccess) {
          if (value.data?.daylog?.isNotEmpty??false) {
            List<DayLog> list = value.data!.daylog;
            for (DayLog log in list) {
              log.babyId = babyId;
              log.date = log.eventTime.split(' ')[0];
              log.status = 0;
              log.localId = 0;
              log.isBackground = 0;
            }
            UserDatabaseUtil.inst.database.dayLogDao.insertDayLogs(list);

            /// 比较缓存数据和服务端数据
            if (list != null && list.isNotEmpty &&
                cache != null && cache.isNotEmpty) {
              list.removeWhere((element) {
                bool exist = false;
                for (DayLog cacheItem in cache) {
                  if (RecordUtil.isSameRecord(element, cacheItem)) {
                    debugPrint('isSameRecord ${element.id}');
                    exist = true;
                    break;
                  }
                }

                return exist;
              });
            }

            if (list.isNotEmpty) {
              _recordNotifier.addData(_currentPage, list);
            }
          }
        } else {
          /// 不需要处理，展示之前的缓存数据即可
        }
      });
    });
  }
}
